﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web.Mvc;
using TimeMachine.Engine;
using TimeMachine.Engine.Agents;
using TimeMachine.Engine.Analytics;
using TimeMachine.Engine.Metrics;
using WebMachine.Models;
using PlotData = WebMachine.Models.PlotData;

namespace WebMachine.Controllers
{
	public class TimelineController : Controller
	{
		private readonly PlotData noSuchProjectPlot =
			new PlotData
				{
					Author = "",
					Metric = "",
					PlotUrl = "../Content/no-such-project.gif"
				};

		private readonly IProjectSettingsStore store = new WebMachineProjectsSettingsStore();

		public ActionResult Plot()
		{
			string projectName = HttpContext.Request.QueryString["project"];
			var model = new TimelineModel { ProjectName = projectName, Projects = store.GetProjectNames() };
			if(store.HasProjectSettings(projectName))
			{
				ProjectInfo info = new InfoAgent(store.Get(projectName)).GetInfo();
				model.Authors = info.Authors;
				model.Metrics = new[] { "InternalRate", "LOC", "CommitRate" };
				NameValueCollection qs = HttpContext.Request.QueryString;
				model.Since = ParseDate(qs["since"], DateTime.Now - TimeSpan.FromDays(182)).Date;
				model.Till = ParseDate(qs["till"], DateTime.Now).Date;
				model.Plots = GetPlots(
					model.ProjectName,
					TimeSpan.FromDays(model.Timeframe),
					(qs.GetValues("author") ?? new string[0]).Select(s => s == "" ? null : s),
					qs.GetValues("metric") ?? model.Metrics,
					model.Since,
					model.Till
					).ToArray();
			}
			else
				model.Plots = new[] { noSuchProjectPlot };
			return View(model);
		}

		private static DateTime ParseDate(string value, DateTime defaultDate)
		{
			if(value == null) return defaultDate;
			DateTime d;
			if(!DateTime.TryParse(value, out d)) return defaultDate;
			return d;
		}

		private IEnumerable<PlotData> GetPlots(
			string projectName,
			TimeSpan timeframe,
			IEnumerable<string> authors,
			IEnumerable<string> metrics,
			DateTime start, DateTime end)
		{
			if(!authors.Any()) authors = new string[] { null };
			IProjectSettings settings = store.Get(projectName);
			var plotter = new PlotAgent(settings);
			return
				from a in authors
				from m in metrics
				select BuildPlotData(plotter, a, m, timeframe, start, end);
		}

		private static PlotData BuildPlotData(PlotAgent plotAgent, string author, string metric,
									   TimeSpan timeframe, DateTime start,
									   DateTime end)
		{
			const int strangeRevisionsCount = 5;
			var plot = plotAgent.GetPlot(metric, author, start, end, strangeRevisionsCount);
			var data =
				new PlotData
					{
						PlotUrl = plot.PlotUrl ?? "../Content/no-data-yet.gif",
						Author = author,
						Metric = metric,
						StrangeRevisions = BuildStrangeRevisions(metric, plot.StrangeRevsAnalysisData)
					};

			return data;
		}

		private static StrangeRevisionsData BuildStrangeRevisions(string metric, StrangeRevsAnalysisData data)
		{
			return data == null ? null :
				new StrangeRevisionsData
					{
						Metric = metric,
						DistributionUrl = data.ValueDistributionPlotUrl,
						StrangeRevsTop = data.StrangeRevs.Select(commitInfo => CreateStrangeRevData(data.Average, commitInfo)).ToArray()
					};
		}

		private static StrangeRevisionData CreateStrangeRevData(double average, CommitMetric commitInfo)
		{
			return
				new StrangeRevisionData
					{
						Author = commitInfo.Commit.Author,
						Date = commitInfo.Commit.Date,
						Message = commitInfo.Commit.Message,
						Revision = commitInfo.Commit.Revision,
						Value = commitInfo.Metric.Value,
						PercentageOfAverage = average != 0.0 ? 100 * commitInfo.Metric.Value / average : 0.0
					};
		}
	}
}